package com.ggb.reactive.controller.user

import com.ggb.reactive.constant.ACTION_FAIL
import com.ggb.reactive.constant.ACTION_SUCCESS
import com.ggb.reactive.constant.SHOPPING_CART_NOT_FIND
import com.ggb.reactive.constant.USER_ID
import com.ggb.reactive.domain.dto.ShoppingCartDTO
import com.ggb.reactive.domain.entity.ShoppingCart
import com.ggb.reactive.extension.log
import com.ggb.reactive.model.Result
import com.ggb.reactive.repository.DishRepository
import com.ggb.reactive.repository.SetmealRepository
import com.ggb.reactive.repository.ShoppingCartRepository
import com.ggb.reactive.service.ShoppingCartService
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import lombok.RequiredArgsConstructor
import org.springframework.beans.BeanUtils
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.bind.annotation.*
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
import java.math.BigDecimal

@RestController
@RequestMapping("/user/shoppingCart")
@RequiredArgsConstructor
@Tag(name = "购物车相关")
class ShoppingCartController(
    private val shoppingCartService: ShoppingCartService,
    private val shoppingCartRepository: ShoppingCartRepository,
    private val dishRepository: DishRepository,
    private val setmealRepository: SetmealRepository

) {
    @PostMapping("/add")
    @Operation(summary = "添加购物车")
    @Transactional
    fun add(@RequestBody shoppingCartDTO: ShoppingCartDTO, exchange: ServerWebExchange): Mono<Result<String>> {
        val userId = (exchange.attributes[USER_ID] as Int).toLong()

        val shoppingCart = ShoppingCart()
        BeanUtils.copyProperties(shoppingCartDTO, shoppingCart)
        shoppingCart.userId = userId

        return shoppingCartService.findShoppingCartByCriteria(shoppingCart)
            .flatMap { it ->

                if (it.isNotEmpty()) {
                    val cart = it.first()
                    val number = cart.number?.plus(1) ?: 0
                    log.info("cart {}",cart)
                    log.info("number {}",number)
                    shoppingCartRepository.updateNumberById(number, cart.id!!)
                } else {

                    val dishMono = shoppingCartDTO.dishId?.let { dishRepository.findById(it) }
                    val setmealMono =  shoppingCartDTO.setmealId?.let { setmealRepository.findById(it) }
                    setmealMono?.flatMap { setmeal ->
                        val item = ShoppingCart()
                        item.userId = userId
                        item.name = setmeal.name
                        item.image = setmeal.image
                        item.amount = setmeal.price
                        item.setmealId = setmeal.id
                        item.number = 1
                        shoppingCartRepository.save(item)
                    }
                        ?: (dishMono?.flatMap { dish ->
                            val item = ShoppingCart()
                            item.userId = userId
                            item.name = dish.name
                            item.image = dish.image
                            item.amount = dish.price
                            item.dishId = dish.id
                            item.number = 1
                            shoppingCartRepository.save(item)
                        } ?: Mono.empty())
                }
            }.map<Result<String>?> {
                Result.success()
            }
            .onErrorResume {
                Mono.just(Result.error(it.message ?: ACTION_FAIL))
            }
    }


    @PostMapping("/sub")
    @Operation(summary = "减去购物车")
    @Transactional
    fun sub(@RequestBody shoppingCartDTO: ShoppingCartDTO,exchange: ServerWebExchange): Mono<Result<String>> {
        val userId = (exchange.attributes[USER_ID] as Int).toLong()

        val shoppingCart = ShoppingCart()
        BeanUtils.copyProperties(shoppingCartDTO, shoppingCart)
        shoppingCart.userId = userId

        return shoppingCartService.findShoppingCartByCriteria(shoppingCart)
            .flatMap {
                val cart = it.firstOrNull() ?: return@flatMap Mono.just(Result.error(SHOPPING_CART_NOT_FIND))
                val number = cart.number?.plus(-1) ?: 0
                if(number == 0){
                    shoppingCartRepository.delete(cart)
                        .then(Mono.fromCallable { Result.success(ACTION_SUCCESS) })
                }else{
                    shoppingCartRepository.updateNumberById(number, cart.id!!)
                        .then(Mono.fromCallable { Result.success(ACTION_SUCCESS) })
                }
            }
            .onErrorResume {
                Mono.just(Result.error(it.message ?: ACTION_FAIL))
            }
    }

    @GetMapping("/list")
    @Operation(summary = "获取购物车列表")
    fun list(exchange: ServerWebExchange): Mono<Result<List<ShoppingCart>>> {
        val userId = (exchange.attributes[USER_ID] as Int).toLong()
        val shoppingCart = ShoppingCart()
        shoppingCart.userId = userId
        return shoppingCartService.findShoppingCartByCriteria(shoppingCart).map {
            Result.success(it)
        }
            .onErrorResume {
                println("error: $it")
                Mono.just(Result.error(it.message ?: ACTION_FAIL))
            }
    }

    @DeleteMapping("/clean")
    @Operation(summary = "清空购物车")
    fun clean(exchange: ServerWebExchange): Mono<Result<String>> {
        val userId = (exchange.attributes[USER_ID] as Int).toLong()
        return shoppingCartRepository.deleteAllByUserId(userId).then(Mono.just(Result.success()))
    }
}